package com.zsj.service;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zsj.channel.SpddService;
import com.zsj.constant.RechargeConstant;
import com.zsj.context.ThreadLocalContext;
import com.zsj.entity.*;
import com.zsj.enums.ErrorCodeEnum;
import com.zsj.enums.OrderStatusEnum;
import com.zsj.enums.ReorderStatusEnum;
import com.zsj.exception.BusinessException;
import com.zsj.mysql.entity.DyMobileRecharge;
import com.zsj.mysql.service.IDyMobileRechargeService;
import com.zsj.util.DateUtil;
import com.zsj.util.IDGenerator;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.MDC;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @Description:
 * @Author:
 * @Date:
 */
@Slf4j
@Service
public class MobileService {

    @Autowired
    private IDyMobileRechargeService mobileRechargeService;

    @Autowired
    private SpddService spddService;

    @Autowired
    private SignService signService;

    @Autowired
    private DiscountService discountService;

    @Autowired
    private IDGenerator idGenerator;

    public RechargeResponse recharge(RechargeRequest request) {
        RechargeResponse response = new RechargeResponse();
        DyMobileRecharge entity = new DyMobileRecharge();
        BeanUtils.copyProperties(request, entity);
        entity.setTimestamp(request.getTimestamp() + "");
        entity.setUrl("/mobile/recharge");
        entity.setSupplierCode(RechargeConstant.SUPPLIER_CODE);

        // 生成订单号
        String orderId = idGenerator.getOrderId();
        MDC.put("selfUid", orderId);
        entity.setChannelChargeNo(orderId);
        entity.setTxnDate(Integer.valueOf(DateUtil.getCurrentDay()));
        // 供应商默认为请求方上送的，供应商有返回则在供应商返回后再更新
        entity.setOriginCarrierCode(request.getCarrierCode());
        entity.setCurrentCarrierCode(request.getCarrierCode());
        // 自己的结算金额，单位为毫
        String selfPrice = discountService.calculateSelfPrice(entity.getAppId(), entity.getCarrierCode(),
                entity.getProductDenomination(), entity.getAdCode());
        if (null == selfPrice) {
            throw new BusinessException(ErrorCodeEnum.PRODUCT_NOT_CONFIGURED);
        }
        entity.setContractPrice(selfPrice);
        try {
            mobileRechargeService.save(entity);
        } catch (DuplicateKeyException dke) {
            log.error("唯一键冲突", dke);

            QueryWrapper<DyMobileRecharge> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("charge_no", request.getChargeNo());
            DyMobileRecharge record = mobileRechargeService.getOne(queryWrapper);
            if (ObjectUtils.isEmpty(record)) {
                log.info("当前月份表未查得，查询上月分表");
                // 默认查询当月的，如果下单是在月末最后一天，查询是在下个月，则此时查不到元交易，需要在上一个月的分表中查询
                record = mobileRechargeService.getByOrderNo(DateUtil.getLastMonth(), request.getChargeNo());
            }

            if (!ObjectUtils.isEmpty(record)) {
                response.setOrderStatus(record.getOrderStatus() + "");
                entity.setChannelChargeNo(record.getChannelChargeNo());
                if (OrderStatusEnum.isFinal(record.getOrderStatus() + "")) {
                    response.setFinishTime(record.getFinishTime());
                }
                // if (Objects.isNull(OrderStatusEnum.findByCode(record.getOrderStatus() + ""))) {
                //     response.setOrderStatus(OrderStatusEnum.PROCESSING.getCode());
                // } else {
                //     response.setChannelOrderNo(record.getChannelChargeNo());
                //     response.setOrderStatus(OrderStatusEnum.findByCode(record.getOrderStatus() + "").getCode());
                // }
            }
            completeResponse(entity, response);
            return response;
        } catch (Exception e) {
            log.error("保存订单异常", e);
            response.setOrderStatus(OrderStatusEnum.FAILED.getCode());
            response.setFinishTime(DateUtil.getCurrentDateTime());
            completeResponse(entity, response);
            return response;
        }
        try {
            spddService.orderRecharge(entity, response);
        } catch (BusinessException be) {
            // 自定义异常时生成Data
            buildRechargeDataBean(request, entity.getChannelChargeNo(), entity.getContractPrice());
            // 此时返回的是失败，更新数据库订单为失败
            updateDb(entity, response, be.getErrorCodeEnum());
            throw be;
        } catch (Exception e) {
            // 通道服务中有捕获异常，按照处理中返回，正常走不到这
            response.setOrderStatus(OrderStatusEnum.PROCESSING.getCode());
            return response;
        }
        completeResponse(entity, response);
        return response;
    }

    public void reorder(DyMobileRecharge entity, RechargeResponse response) {
        try {
            spddService.orderRecharge(entity, response);
        } catch (BusinessException be) {
            // 此时返回的是失败，更新数据库订单为失败
            updateDb(entity, response, be.getErrorCodeEnum());
        } catch (Exception e) {
            // 通道服务中有捕获异常，按照处理中返回，正常走不到这
            response.setOrderStatus(OrderStatusEnum.PROCESSING.getCode());
        }
        if (StringUtils.isNotBlank(response.getSupplierOrderNo())) {
            log.info("重发时通道返回了供应商订单号，标记为重发成功");
            entity.setReorderStatus(ReorderStatusEnum.SUCCESS.getCode());
        }
        log.info("更新重发状态、重发次数、重发时间");
        boolean flag = mobileRechargeService.updateReorder(String.valueOf(entity.getTxnDate()).substring(0, 6),
                entity.getReorderStatus(), DateUtil.getCurrentDateTime(), entity.getChargeNo());
        log.info("更新重发状态等结果:{}", flag);
    }

    public RechargeResponse orderQuery(OrderQueryRequest request) {
        RechargeResponse response = new RechargeResponse();
        QueryWrapper<DyMobileRecharge> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("charge_no", request.getChargeNo());
        DyMobileRecharge record = mobileRechargeService.getOne(queryWrapper);
        if (ObjectUtils.isEmpty(record)) {
            log.info("当前月份表未查得，查询上月分表");
            // 默认查询当月的，如果下单是在月末最后一天，查询是在下个月，则此时查不到元交易，需要在上一个月的分表中查询
            record = mobileRechargeService.getByOrderNo(DateUtil.getLastMonth(), request.getChargeNo());
            if (ObjectUtils.isEmpty(record)) {
                log.info("根据订单号{}未查询到订单", request.getChargeNo());
                buildRechargeDataBean(request, null, null);
                throw new BusinessException(ErrorCodeEnum.ORDER_NOT_EXIST);
            }
        }
        if (OrderStatusEnum.isFinal(record.getOrderStatus() + "")) {
            log.info("订单{}已为终态，直接返回", request.getChargeNo());
            response.setOrderStatus(record.getOrderStatus() + "");
            response.setContractPrice(record.getContractPrice());
            response.setFinishTime(record.getFinishTime());
            response.setOriginCarrierCode(record.getOriginCarrierCode());
            response.setCurrentCarrierCode(record.getCurrentCarrierCode());
        } else {
            log.info("订单{}非终态，开始查询", request.getChargeNo());
            try {
                // 由于dy要求失败的code要返回错误码，通道服务根据错误码映射throw自定义异常，
                // catch后要更新数据库，所以response作为参数以便能够获取到里面的值，否则update时取不到response中的字段
                spddService.orderQuery(record, response);
            } catch (BusinessException be) {
                // 自定义异常时生成Data
                buildRechargeDataBean(request, record.getChannelChargeNo(), record.getContractPrice(), response.getFinishTime());
                // 此时返回的是失败，更新数据库订单为失败
                updateDb(record, response, be.getErrorCodeEnum());
                throw be;
            } catch (Exception e) {
                // 通道服务中有捕获异常，按照处理中返回，正常走不到这
                response.setOrderStatus(OrderStatusEnum.PROCESSING.getCode());
                completeResponse(record, response);
                return response;
            }
            // 根据查询结果更新数据库
            updateDb(record, response, ErrorCodeEnum.SUCCESS);
        }
        completeResponse(record, response);
        return response;
    }

    public ProductQueryResponse productQuery(ProductQueryRequest request) {
        return spddService.productQuery(request);
    }

    /**
     * 非成功时构造响应Data
     *
     * @param request
     * @param channelOrderNo
     */
    public void buildRechargeDataBean(BaseRequest request, String channelOrderNo, String price) {
        buildRechargeDataBean(request, channelOrderNo, price, DateUtil.getCurrentDateTime());
    }

    /**
     * 针对有明确的完成时间的失败时构建Data
     *
     * @param request
     * @param channelOrderNo
     * @param price
     * @param finishTime
     */
    public void buildRechargeDataBean(BaseRequest request, String channelOrderNo, String price, String finishTime) {
        try {
            RechargeDataBean bean = new RechargeDataBean();
            bean.setAppId(request.getAppId());
            bean.setSupplierCode(RechargeConstant.SUPPLIER_CODE);
            bean.setChargeNo(request.getChargeNo());
            if (StringUtils.isNotBlank(channelOrderNo)) {
                bean.setChannelOrderNo(channelOrderNo);
            }
            bean.setOrderStatus(OrderStatusEnum.FAILED.name());
            bean.setContractPrice(StringUtils.isBlank(price) ? "0" : price);
            bean.setFinishTime(finishTime);
            ObjectMapper beanMapper = new ObjectMapper();
            Map<String, Object> beanMap = beanMapper.readValue(JSONObject.toJSONString(bean), Map.class);
            bean.setSign(signService.sign(beanMap));
            ThreadLocalContext.RECHARGE_DATA_THREAD_LOCAL.set(JSONObject.toJSONString(bean));
        } catch (Exception e) {
            log.error("非成功时构造响应Data异常", e);
        }
    }

    /**
     * 更新数据库
     *
     * @param record
     * @param response
     */
    private void updateDb(DyMobileRecharge record, RechargeResponse response, ErrorCodeEnum errorCodeEnum) {
        boolean needUpdate = false;
        if (StringUtils.isNotBlank(response.getContractPrice())
                && !record.getContractPrice().equals(response.getContractPrice())) {
            log.info("更新自己的结算金额");
            needUpdate = true;
            record.setContractPrice(response.getContractPrice());
        }
        if (StringUtils.isBlank(record.getSupplierContractPrice()) || !record.getSupplierContractPrice().equals(response.getSupplierContractPrice())) {
            log.info("更新供应商结算金额");
            needUpdate = true;
            record.setSupplierContractPrice(response.getSupplierContractPrice());
        }
        if (StringUtils.isBlank(record.getSupplierOrderNo()) || !record.getSupplierOrderNo().equals(response.getSupplierOrderNo())) {
            log.info("更新供应商订单号");
            needUpdate = true;
            record.setSupplierOrderNo(response.getSupplierOrderNo());
        }
        if (StringUtils.isNotBlank(response.getOriginCarrierCode())
                && !response.getOriginCarrierCode().equals(record.getOriginCarrierCode())) {
            log.info("更新原运营商");
            needUpdate = true;
            record.setOriginCarrierCode(response.getOriginCarrierCode());
        }
        if (StringUtils.isNotBlank(response.getCurrentCarrierCode())
                && !response.getCurrentCarrierCode().equals(record.getCurrentCarrierCode())) {
            log.info("更新现运营商");
            needUpdate = true;
            record.setCurrentCarrierCode(response.getCurrentCarrierCode());
        }
        if (null != errorCodeEnum && !errorCodeEnum.getCode().equals(record.getReturnCode())) {
            log.info("更新返回码");
            needUpdate = true;
            record.setReturnCode(errorCodeEnum.getCode());
        }
        if (null != errorCodeEnum && !errorCodeEnum.getMsg().equals(record.getReturnMessage())) {
            log.info("更新返回信息");
            needUpdate = true;
            record.setReturnMessage(errorCodeEnum.getMsg());
        }
        // 查询终态后更新数据库
        if (OrderStatusEnum.isFinal(response.getOrderStatus())) {
            needUpdate = true;
            record.setOrderStatus(Integer.valueOf(response.getOrderStatus()));
            record.setFinishTime(response.getFinishTime());
            record.setFinishDate(Integer.valueOf(response.getFinishTime().substring(0, 10).replaceAll("-", "")));
            // 成功时赋值成功时间
            if (OrderStatusEnum.SUCCESS.getCode().equals(response.getOrderStatus())) {
                record.setSuccessTime(response.getFinishTime());
            }
        }
        if (needUpdate) {
            log.info("更新订单表");
            // 根据交易日期获取月份
            String month = String.valueOf(record.getTxnDate()).substring(0, 6);
            mobileRechargeService.updateFinal(month, record);
        }
    }

    /**
     * 根据请求补全响应字段
     *
     * @param entity
     * @param response
     */
    private void completeResponse(DyMobileRecharge entity, RechargeResponse response) {
        try {
            // 下游供应商订单号透传完后置空
            response.setSupplierOrderNo(null);
            response.setAppId(entity.getAppId());
            response.setSupplierCode(entity.getSupplierCode());
            response.setChargeNo(entity.getChargeNo());
            response.setChannelOrderNo(entity.getChannelChargeNo());
            // 订单状态转换
            OrderStatusEnum statusEnum = OrderStatusEnum.findByCode(response.getOrderStatus());
            if (Objects.isNull(statusEnum)) {
                response.setOrderStatus(OrderStatusEnum.FAILED.name());
            } else {
                response.setOrderStatus(statusEnum.name());
            }
            response.setContractPrice(entity.getContractPrice());

            if (OrderStatusEnum.SUCCESS.name().equals(response.getOrderStatus())) {
                response.setOriginCarrierCode(entity.getOriginCarrierCode());
                response.setCurrentCarrierCode(entity.getOriginCarrierCode());
                response.setAdCode(entity.getAdCode());
                response.setProductDenomination(entity.getProductDenomination());
            }


            // 签名
            ObjectMapper mapper = new ObjectMapper();
            Map<String, Object> responseMap = mapper.readValue(JSONObject.toJSONString(response), Map.class);
            String sign = signService.sign(responseMap);
            response.setSign(sign);
        } catch (Exception e) {
            log.error("根据请求补全响应字段异常", e);
        }
    }

    public static void main(String[] args) {
        List<MaintainInfo> maintainInfoList = new ArrayList<>();
        MaintainInfo a = new MaintainInfo();
        a.setAdCode("code");
        a.setStatus(0);
        MaintainInfo b = new MaintainInfo();
        b.setAdCode("code");
        b.setStatus(0);
        MaintainInfo c = new MaintainInfo();
        c.setAdCode("code");
        c.setStatus(0);

        maintainInfoList.add(a);
        maintainInfoList.add(b);
        maintainInfoList.add(c);

        WebResponse d = WebResponse.success(maintainInfoList);

        System.out.println(JSONObject.toJSONString(d));
    }

}
